#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <set>
#include "Log.hpp"

const std::string sep = " ";
class Command
{
private:
    void LoadConf()
    {
        // 1. 打开文件
        std::ifstream in(_cond_path);
        if (!in.is_open())
        {
            LOG(FATAL, "open %s error\n", _cond_path.c_str());
            return;
        }
        // 读文件
        std::string line;
        while (std::getline(in, line))
        {
            LOG(DEBUG, "load commad %s success\n", line.c_str());
            // 插入数据
            _safe_cmd.insert(line);
        }
        // 关闭文件
        in.close();
    }

    std::string PrefixCommand(const std::string &cmd)
    {
        if (cmd.empty()) return std::string();
        auto pos = cmd.find(sep);
        if (pos == std::string::npos)
            return cmd;
        else return cmd.substr(0, pos);
    }

    bool SafeCheck(const std::string &cmd)
    {
        std::string prefix = PrefixCommand(cmd);
        auto ite = _safe_cmd.find(prefix);
        if (ite == _safe_cmd.end())
            return false;
        return true;
    }

public:
    Command(const std::string &cond_path) : _cond_path(cond_path)
    {
        LoadConf();
    }
    std::string Excute(const std::string &cmd)
    {
        // 1. fork && pipe
        // 2. excut
        // 2.1 dup
        std::string result = " ";
        if (SafeCheck(cmd))
        {
            FILE *fp = popen(cmd.c_str(), "r"); // popen函数会自动创建一个子进程并创建管道，子进程或执行cmd命令，_modes是类似于文件读取的一样
            if (nullptr == fp)
            {
                return "faild";
            }
            // 读文件
            char buffer[1024];
            std::cout << "begin read" << std::endl;
            while (fgets(buffer, sizeof(buffer), fp) != NULL)
            {
                result += buffer;
                std::cout << "touch file" << std::endl;
            }
            std::cout << "end of read" << std::endl;
            pclose(fp);
        }
        else
        {
            return "坏人\n";
        }
        return result;
    }
    ~Command()
    {
    }

private:
    std::set<std::string> _safe_cmd;
    std::string _cond_path;
};
